package orxatas.travelme.sync;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import android.content.ContentValues;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import orxatas.travelme.activity.AsyncActivity;
import orxatas.travelme.databases.TravelmeDatabase;
import orxatas.travelme.entity.Comment;
import orxatas.travelme.entity.Group;
import orxatas.travelme.manager.AccountManager;
import orxatas.travelme.manager.DataManager;
import orxatas.travelme.manager.GroupManager;
import orxatas.travelme.sync.SyncData.SyncDataType;
import orxatas.travelme.sync.exceptions.ImposibleAcceptInvitation;
import orxatas.travelme.sync.exceptions.ImposibleRemoveFriendFrom;

/**
 * Módulo de sincronización de grupos. Será quien maneje los datos locales sincronizados.
 * */
public class SyncGroups extends SyncOptions {
	
	/**
	 * True si hay una petición de actualización en curso. En caso contrario false.
	 * */
	static private boolean synchronizing = false;
	
	/**
	 * Lista de grupos locales.
	 * */
	static private ArrayList<Group> groupList = null;
	
	/**
	 * La instancia del groupManager.
	 * */
	private GroupManager groupManagerInstance;
	
	/**
	 * Base de datos.
	 * */
	private SQLiteDatabase trvlmdb;
	private TravelmeDatabase databaseHelper;

	/**
	 * Contexto de la aplicación. Actividad.
	 * */
	private AsyncActivity asyncActivity;

	private SyncDataType syncData;
	
	/**
	 * SyncGroups Constructor.
	 * @param groupManagerInstance La instancia del groupManager.
	 * @param asyncActivity La actividad
	 * */
	public SyncGroups(GroupManager groupManagerInstance, AsyncActivity asyncActivity){
		this.groupManagerInstance = groupManagerInstance;
		this.asyncActivity = asyncActivity;
		
		databaseHelper = new TravelmeDatabase(asyncActivity.getActivity(), new AccountManager(asyncActivity).getUserLogged().getId());
		
		//if(checkIfSyncIsNeeded()) synchronize(null);
	}
	
	/**
	 * Petición para obtener los grupos. Devuelve inmediatamente los grupos locales. Los datos pueden estar desactualizados
	 * 
	 * @return Lista de grupos locales.
	 * */
	public ArrayList<Group> getGroups(){
		loadFromDB();
		return groupList;
	}
	
	/**
	 * Comprueba si actualmente existe alguna petición de sincronización en curso.
	 * 
	 * @return  Devuelve true si hay una petición de actualización en curso. En caso contrario devuelve false.
	 * */
	public boolean isSynchronizing(){
		return synchronizing;
	}
	
	/**
	 * Recupera toda la lista de grupos almacenada localmente.
	 * */
	private void loadFromDB(){
		groupList = new ArrayList<Group>();
		
		trvlmdb = databaseHelper.getWritableDatabase();
		Cursor cgl = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.GROUP_TNAME+" WHERE "+TravelmeDatabase.GROUP_TOREMOVE+" = 0 ORDER BY "+TravelmeDatabase.GROUP_CLASTUPDATE+" DESC", null);
		
		int cid_id = cgl.getColumnIndex(TravelmeDatabase.GROUP_CID);
		int cid_idoff = cgl.getColumnIndex(TravelmeDatabase.GROUP_CIDL);
		int cid_name = cgl.getColumnIndex(TravelmeDatabase.GROUP_CGROUPNAME);
		int cid_owner = cgl.getColumnIndex(TravelmeDatabase.GROUP_COWNER);
		int cid_lu = cgl.getColumnIndex(TravelmeDatabase.GROUP_CLASTUPDATE);
		
		while(cgl.moveToNext()){		
			//Basic group data
			int groupId = cgl.getInt(cid_id);
			int groupIdOff = cgl.getInt(cid_idoff);
			String groupName = cgl.getString(cid_name);
			int ownerId = cgl.getInt(cid_owner);
			int lastUpdate = cgl.getInt(cid_lu);
	
			Group g = new Group(groupIdOff, groupName, ownerId);
			g.setIdOnline(groupId);
			g.setLastUpdate(lastUpdate);
			
			//Load Comments.
			Cursor ccl = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.COMMENT_TNAME+" WHERE "+
					TravelmeDatabase.COMMENT_CIDGROUP+" = "+groupIdOff+" ORDER BY "+TravelmeDatabase.COMMENT_CLASTUPDATE+" DESC", null);
			int cidcm_idoff = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CIDL);
			int cidcm_idon = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CID);
			int cidcm_idautor = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CAUTOR);
			int cidcm_c = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CC);
			int cidcm_idplace = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CIDPLACE);
			int cidcm_lastupdate = ccl.getColumnIndex(TravelmeDatabase.COMMENT_CLASTUPDATE);

			ArrayList<Comment> commentList = new ArrayList<Comment>();
			while(ccl.moveToNext()){
				int c_idoff = ccl.getInt(cidcm_idoff);
				int c_idon = ccl.getInt(cidcm_idon);
				int c_idautor = ccl.getInt(cidcm_idautor);
				String c_c = ccl.getString(cidcm_c);
				int c_idplace = ccl.getInt(cidcm_idplace);
				int c_lastupdate = ccl.getInt(cidcm_lastupdate);
				
				Comment comment = new Comment(c_idoff, c_c, c_idautor, c_idplace);
				comment.setIdOnline(c_idon);
				comment.setLastUpdate(c_lastupdate);
				
				commentList.add(comment);
			}
			g.setComments(commentList);
			ccl.close();
			
			//Load user members list to group.
			Cursor cml = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.USERINGROUP_TNAME+" WHERE "+
					TravelmeDatabase.USERINGROUP_CIDLGROUP+" = "+groupIdOff+" AND NOT ("+
					TravelmeDatabase.USERINGROUP_CTOREMOVE+" = 1 OR "+
					TravelmeDatabase.USERINGROUP_CTOREJECT+" = 1)", null);
			int cidml_iduser = cml.getColumnIndex(TravelmeDatabase.USERINGROUP_CIDUSER);
			
			ArrayList<Integer> membersList = new ArrayList<Integer>();
			while(cml.moveToNext()){
				int m_iduser = cml.getInt(cidml_iduser);
				membersList.add(m_iduser);
			}
			g.setUsers(membersList);
			cml.close();
			
			//Load places list of the group
			Cursor cpl = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.PLACEINGROUP_TNAME+" WHERE "+
					TravelmeDatabase.PLACEINGROUP_CIDGROUP+" = "+groupIdOff+" AND "+
					TravelmeDatabase.PLACEINGROUP_CMARKTODEL+" <> 1", null);
			int cidpl_idplace = cpl.getColumnIndex(TravelmeDatabase.PLACEINGROUP_CIDPLACE);
			
			ArrayList<Integer> placesList = new ArrayList<Integer>();
			while(cpl.moveToNext()){
				int p_idplace = cpl.getInt(cidpl_idplace);
				placesList.add(p_idplace);
			}
			g.setPlaces(placesList);
			cpl.close();
			
			//Save loaded group to groupList.
			groupList.add(g);
		}
		cgl.close();
		trvlmdb.close();
	}
	
	/**
	 * Comprueba si es necesario sincronizar datos.
	 * 
	 * @return True si se considera que los datos están desactualizados.
	 * */
	private boolean checkIfSyncIsNeeded(){
		//TODO
		return true;
	}
	
	private class AnswerGroupList extends Answer<ArrayList<Group>>{}
	/**
	 * Es la clase encargada de realizar la llamada asincrona para sincronizar la lista de grupos local.
	 * */
	private class GroupSyncCall extends AsyncInternetConnection{
		GroupSyncCall() {
			super(TRVLMWS);
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_OM, ACTION_OM_LIST);
			addGETParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			boolean groupIsChanged = false;
			try {
				Answer<ArrayList<Group>> answer = new ParseAnswer<AnswerGroupList>().parse(response, true, AnswerGroupList.class);
				
				if(answer.getState() != 0){
					Log.e("SYNC", "There was an error with group sync call.");
					return;
				}
				
				ArrayList<Group> gl = answer.getObj();
				trvlmdb = databaseHelper.getWritableDatabase();
				for(Group g: gl){
					Group oldg = null;
					for(Group auxg: groupList){
						if(g.getIdOnline() == auxg.getIdOnline()) {
							oldg = auxg;
							break;
						}
					}
					
					//The group already existed and it was updated.
					if(oldg != null && oldg.getLastUpdate() < g.getLastUpdate()){
						groupIsChanged = true;
						ContentValues v = new ContentValues();
						v.put(TravelmeDatabase.GROUP_CGROUPNAME, g.getName());
						v.put(TravelmeDatabase.GROUP_CLASTUPDATE, g.getLastUpdate());
						trvlmdb.update(TravelmeDatabase.GROUP_TNAME, v, TravelmeDatabase.GROUP_CIDL+" = "+oldg.getIdOffline(), null);
						
						for(Comment c: g.getComments()){
							Comment oldc = null;
							for(Comment auxc: oldg.getComments()){
								if(auxc.getIdOnline() == c.getIdOnline()){
									oldc = auxc;
									break;
								}
							}
							
							if(oldc != null && oldc.getLastUpdate() < c.getLastUpdate()){
								ContentValues vc = new ContentValues();
								vc.put(TravelmeDatabase.COMMENT_CC, c.getComment());
								vc.put(TravelmeDatabase.COMMENT_CLASTUPDATE, c.getLastUpdate());
								trvlmdb.update(TravelmeDatabase.COMMENT_TNAME, vc, TravelmeDatabase.COMMENT_CIDL+" = "+c.getIdOffline(), null);
							
							} else if(oldc == null) {
								ContentValues vc = new ContentValues();
								vc.put(TravelmeDatabase.COMMENT_CID, c.getIdOnline());
								vc.put(TravelmeDatabase.COMMENT_CIDGROUP, oldg.getIdOffline());
								vc.put(TravelmeDatabase.COMMENT_CAUTOR, c.getIdAutor());
								vc.put(TravelmeDatabase.COMMENT_CC, c.getComment());
								vc.put(TravelmeDatabase.COMMENT_CIDPLACE, c.getIdPlaceRelated());
								vc.put(TravelmeDatabase.COMMENT_CLASTUPDATE, c.getLastUpdate());
								vc.put(TravelmeDatabase.COMMENT_CSYNC, 1);
								trvlmdb.insert(TravelmeDatabase.COMMENT_TNAME, null, vc);
							}
						}
						
						//Add newer users.
						for(int m: g.getUsers()){
							boolean memberWas = false;
							for(int oldm: oldg.getUsers()){
								if(m == oldm) {
									memberWas = true;
									break;
								}
							}
							if(!memberWas) {
								ContentValues vm = new ContentValues();
								vm.put(TravelmeDatabase.USERINGROUP_CIDUSER, m);
								vm.put(TravelmeDatabase.USERINGROUP_CIDLGROUP, oldg.getIdOffline());
								vm.put(TravelmeDatabase.USERINGROUP_CSYNC, 1);
								trvlmdb.insert(TravelmeDatabase.USERINGROUP_TNAME, null, vm);
							}
						}
						
						//Remove users that don't are members.
						for(int oldm: oldg.getUsers()){
							boolean memberWas = false;
							for(int m: g.getUsers()){
								if(oldm == m){
									memberWas = true;
									break;
								}
							}
							if(!memberWas){
								trvlmdb.delete(TravelmeDatabase.USERINGROUP_TNAME, TravelmeDatabase.USERINGROUP_CIDLGROUP+" = "+oldg.getIdOffline()+
										" AND "+TravelmeDatabase.USERINGROUP_CIDUSER+" = "+oldm, null);
							}
						}
						
						//Rel with new places.
						for(int p: g.getPlaces()){
							boolean placeWas = false;
							for(int oldp: oldg.getPlaces()){
								if(p == oldp){
									placeWas = true;
									break;
								}
							}
							if(!placeWas){
								ContentValues vp = new ContentValues();
								vp.put(TravelmeDatabase.PLACEINGROUP_CIDGROUP, oldg.getIdOffline());
								vp.put(TravelmeDatabase.PLACEINGROUP_CIDPLACE, p);
								vp.put(TravelmeDatabase.PLACEINGROUP_CSYNC, 1);
								trvlmdb.insert(TravelmeDatabase.PLACEINGROUP_TNAME, null, vp);
							}
						}
						
						//Remove old places
						for(int oldp: oldg.getPlaces()){
							boolean placeWas = false;
							for(int p: g.getPlaces()){
								if(oldp == p){
									placeWas = true;
									break;
								}
							}
							if(!placeWas){
								trvlmdb.delete(TravelmeDatabase.PLACEINGROUP_TNAME, TravelmeDatabase.PLACEINGROUP_CIDGROUP+" = "+oldg.getIdOffline()+
										" AND "+TravelmeDatabase.PLACEINGROUP_CIDPLACE+" = "+oldp, null);
							}
						}
						
					} else if(oldg == null) { //The group didn't exists.
						groupIsChanged = true;
						ContentValues vg= new ContentValues();
						vg.put(TravelmeDatabase.GROUP_CID, g.getIdOnline());
						vg.put(TravelmeDatabase.GROUP_CGROUPNAME, g.getName());
						vg.put(TravelmeDatabase.GROUP_CLASTUPDATE, g.getLastUpdate());
						vg.put(TravelmeDatabase.GROUP_COWNER, g.getOwner());
						int groupID = (int) trvlmdb.insert(TravelmeDatabase.GROUP_TNAME, null, vg);
						
						for(Comment c: g.getComments()){
							ContentValues vc = new ContentValues();
							vc.put(TravelmeDatabase.COMMENT_CID, c.getIdOnline());
							vc.put(TravelmeDatabase.COMMENT_CAUTOR, c.getIdAutor());
							vc.put(TravelmeDatabase.COMMENT_CC, c.getComment());
							vc.put(TravelmeDatabase.COMMENT_CIDGROUP, groupID);
							vc.put(TravelmeDatabase.COMMENT_CIDPLACE, c.getIdPlaceRelated());
							vc.put(TravelmeDatabase.COMMENT_CLASTUPDATE, c.getLastUpdate());
							vc.put(TravelmeDatabase.COMMENT_CSYNC, 1);
							trvlmdb.insert(TravelmeDatabase.COMMENT_TNAME, null, vc);
						}
						
						for(int u: g.getUsers()){
							ContentValues vu = new ContentValues();
							vu.put(TravelmeDatabase.USERINGROUP_CIDLGROUP, groupID);
							vu.put(TravelmeDatabase.USERINGROUP_CIDUSER, u);
							vu.put(TravelmeDatabase.USERINGROUP_CSYNC, 1);
							trvlmdb.insert(TravelmeDatabase.USERINGROUP_TNAME, null, vu);
						}
						
						for(int p: g.getPlaces()){
							ContentValues vp = new ContentValues();
							vp.put(TravelmeDatabase.PLACEINGROUP_CIDGROUP, groupID);
							vp.put(TravelmeDatabase.PLACEINGROUP_CIDPLACE, p);
							vp.put(TravelmeDatabase.PLACEINGROUP_CSYNC, 1);
							trvlmdb.insert(TravelmeDatabase.PLACEINGROUP_TNAME, null, vp);
						}
					}
				}
				for(Group oldg: groupList){
					boolean exists = false;
					for(Group g: gl){
						if(oldg.getIdOnline() == g.getIdOnline()) {
							exists = true;
							break;
						}
					}
					if(!exists && oldg.getIdOnline() != -1){
						groupIsChanged = true;
						trvlmdb.delete(TravelmeDatabase.USERINGROUP_TNAME, TravelmeDatabase.USERINGROUP_CIDLGROUP+" = "+oldg.getIdOffline(), null);
						trvlmdb.delete(TravelmeDatabase.COMMENT_TNAME, TravelmeDatabase.COMMENT_CIDGROUP+" = "+oldg.getIdOffline(), null);
						trvlmdb.delete(TravelmeDatabase.PLACEINGROUP_TNAME, TravelmeDatabase.PLACEINGROUP_CIDGROUP+" = "+oldg.getIdOffline(), null);
						
						trvlmdb.delete(TravelmeDatabase.GROUP_TNAME, TravelmeDatabase.GROUP_CIDL+" = "+oldg.getIdOffline(), null);
					}
				}
				trvlmdb.close();
			} catch (WithoutObject e) {
				Log.e("SYNC", "Bad sync. Groups can't be sync.");
			}
			
			DataManager dm = new DataManager(asyncActivity);

			if(groupIsChanged){
				dm.asyncNotice(AsyncNoticeCode.GROUPS_CHANGED);
			}
			
			
			//Next to sync
			if(syncData != null){
				dm.syncThis(syncData);
				syncData = null;
			} else
				dm.syncInProgressEnd();
			
			synchronizing = false;
		}
	}
	
	private class AnswerComment extends Answer<Comment>{};
	private class NewCommentCall extends AsyncInternetConnection{
		
		public final Comment comment;
		
		NewCommentCall(int idGroup, Comment comment) {
			super(TRVLMWS);
			this.comment = comment;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_ADDC);
			pairs.add(new BasicNameValuePair("gid", ""+groupManagerInstance.getGroup(idGroup).getIdOnline()));
			int idp = comment.getIdPlaceRelated();
			if(idp > 0) pairs.add(new BasicNameValuePair("idp", ""+idp));
			
			addGETParams(pairs);
			
			pairs = new ArrayList<NameValuePair>();
			pairs.add(new BasicNameValuePair("msg", comment.toString()));
			addPOSTParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			trvlmdb = databaseHelper.getWritableDatabase();
			try {
				Answer<Comment> answer = new ParseAnswer<AnswerComment>().parse(response, true, AnswerComment.class);
				
				if(answer.getState() != 0) return;
				Comment syncComment = answer.getObj();
				
				ContentValues v = new ContentValues();
				v.put(TravelmeDatabase.COMMENT_CID, syncComment.getIdOnline());
				v.put(TravelmeDatabase.COMMENT_CLASTUPDATE, syncComment.getLastUpdate());
				trvlmdb.update(TravelmeDatabase.COMMENT_TNAME, v, TravelmeDatabase.COMMENT_CIDL+" = "+comment.getIdOffline(), null);
				
				//Update data of the comment.
				comment.setIdOnline(syncComment.getIdOnline());
				comment.setLastUpdate(syncComment.getLastUpdate());

				
			} catch (WithoutObject e) {
				trvlmdb.delete(TravelmeDatabase.COMMENT_TNAME, TravelmeDatabase.COMMENT_CIDL+" = "+comment.getIdOffline(), null);
			}
			trvlmdb.close();
		}
	}

	private class AnswerGroup extends Answer<Group>{};
	private class NewGroupCall extends AsyncInternetConnection{

		final private Group group;
		
		public NewGroupCall(Group group) {
			super(TRVLMWS);
			this.group = group;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_OM, ACTION_OM_ADD);
			pairs.add(new BasicNameValuePair("name", group.getName()));
			
			addGETParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			try {
				Answer<Group> answer = new ParseAnswer<AnswerGroup>().parse(response, true, AnswerGroup.class);
				if(answer.getState() != 0) return;
				
				Group newGroup = answer.getObj();
				
				trvlmdb = databaseHelper.getWritableDatabase();
				ContentValues v = new ContentValues();
				v.put(TravelmeDatabase.GROUP_CID, newGroup.getIdOnline());
				v.put(TravelmeDatabase.GROUP_CLASTUPDATE, newGroup.getLastUpdate());
				
				trvlmdb.update(TravelmeDatabase.GROUP_TNAME, v, TravelmeDatabase.GROUP_CIDL+" = "+group.getIdOffline(), null);
				trvlmdb.close();
				
				group.setIdOnline(newGroup.getIdOnline());
				group.setLastUpdate(newGroup.getLastUpdate());
				
			} catch (WithoutObject e) {
				trvlmdb = databaseHelper.getWritableDatabase();
				trvlmdb.delete(TravelmeDatabase.GROUP_TNAME, TravelmeDatabase.GROUP_CIDL+" = "+group.getIdOffline(), null);
				trvlmdb.close();
			}
		}
		
	}
	
	/**
	 * Fuerza la ejecuón de una sincronización siempre y cuando no haya una petición en curso.
	 * */
	public void synchronize(SyncDataType syncData){
		if(synchronizing) return;
		
		this.syncData = syncData;
		synchronizing = true;
		new DataManager(asyncActivity).syncInProgress();
		new GroupSyncCall().execute();
	}

	
	/**
	 * Crea un nuevo grupo con una petición asíncrona.
	 * 
	 * @param groupName El nombre del grupo.
	 * 
	 * @return El grupo nuevo creado. Si devuelve null entonces el grupo no se ha podido crear.
	 * */
	public Group createGroup(String name){
		trvlmdb = databaseHelper.getWritableDatabase();
		
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.GROUP_CGROUPNAME, name);
		v.put(TravelmeDatabase.GROUP_COWNER, new AccountManager(asyncActivity).getUserLogged().getId());
		int lastId = (int) trvlmdb.insert(TravelmeDatabase.GROUP_TNAME, null, v);
		
		ContentValues vug = new ContentValues();
		vug.put(TravelmeDatabase.USERINGROUP_CIDLGROUP, lastId);
		int myself = new AccountManager(asyncActivity).getUserLogged().getId();
		vug.put(TravelmeDatabase.USERINGROUP_CIDUSER, myself);
		trvlmdb.insert(TravelmeDatabase.USERINGROUP_TNAME, null, vug);
		
		trvlmdb.close();
		
		Group newGroup = new Group(lastId, name, new AccountManager(asyncActivity).getUserLogged().getId());
		newGroup.setComments(new ArrayList<Comment>());
		
		ArrayList<Integer> members = new ArrayList<Integer>();
		members.add(myself);
		newGroup.setUsers(members);
		newGroup.setPlaces(new ArrayList<Integer>());
		newGroup.setLastUpdate((int) (new Date().getTime()/1000));
		
		new NewGroupCall(newGroup).execute();
		
		return newGroup;
	}
	
	/**
	 * Crea un comentario en un grupo.
	 * 
	 * @param idGroup Identificador del grupo
	 * @param commentText Texto del comentario
	 * 
	 * @return El nuevo comentario
	 * */
	public Comment addCommentTo(int idGroup, String commentText){
		trvlmdb = databaseHelper.getWritableDatabase();
		
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.COMMENT_CC, commentText);
		int idmyself = new AccountManager(asyncActivity).getUserLogged().getId();
		v.put(TravelmeDatabase.COMMENT_CAUTOR, idmyself);
		v.put(TravelmeDatabase.COMMENT_CIDGROUP, idGroup);
		int lastID = (int) trvlmdb.insert(TravelmeDatabase.COMMENT_TNAME, null, v);
		
		trvlmdb.close();
		
		Comment newC = new Comment(lastID, commentText);
		newC.setIdAutor(idmyself);
		newC.setLastUpdate((int) (new Date().getTime()/1000));
		new NewCommentCall(idGroup, newC).execute();
		
		return newC;
	}
	
	/**
	 * Crea un comentario de un grupo relacionado con un lugar.
	 * 
	 * @param idGroup Identificador del grupo
	 * @param commentText Texto del comentario
	 * @param idPlace Identificador de un lugar
	 * 
	 * @return El nuevo comentario
	 * */
	public Comment addCommentTo(int idGroup, String commentText, int idPlace){
		
		trvlmdb = databaseHelper.getWritableDatabase();
		
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.COMMENT_CC, commentText);
		v.put(TravelmeDatabase.COMMENT_CIDPLACE, idPlace);
		int idmyself = new AccountManager(asyncActivity).getUserLogged().getId();
		v.put(TravelmeDatabase.COMMENT_CAUTOR, idmyself);
		v.put(TravelmeDatabase.COMMENT_CIDGROUP, idGroup);
		int lastid = (int) trvlmdb.insert(TravelmeDatabase.COMMENT_TNAME, null, v);
		
		trvlmdb.close();
		
		Comment newC = new Comment(lastid, commentText, new AccountManager(asyncActivity).getUserLogged().getId(), idPlace);
		newC.setLastUpdate((int) (new Date().getTime()/1000));
		newC.setIdAutor(idmyself);
		new NewCommentCall(idGroup, newC).execute();
		
		return newC;
	}
	
	private class NewAddFriendToCall extends AsyncInternetConnection{
		
		final private int idGroup;
		final private int idFriend;

		public NewAddFriendToCall(int idGroup, int idFriend) {
			super(TRVLMWS);
			
			this.idFriend = idFriend;
			this.idGroup = idGroup;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_ADDF);
			pairs.add(new BasicNameValuePair("gid", ""+groupManagerInstance.getGroup(idGroup).getIdOnline()));
			pairs.add(new BasicNameValuePair("fid", ""+idFriend));
			
			addGETParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
			if(answer.getState() == 0) {
				trvlmdb = databaseHelper.getWritableDatabase();
				ContentValues v = new ContentValues();
				v.put(TravelmeDatabase.USERINGROUP_CSYNC, true);
				trvlmdb.update(TravelmeDatabase.USERINGROUP_TNAME, v, TravelmeDatabase.USERINGROUP_CIDUSER+" = "+idFriend+" AND "+TravelmeDatabase.USERINGROUP_CIDLGROUP+" = "+idGroup, null);
				trvlmdb.close();
			} else {
				trvlmdb = databaseHelper.getWritableDatabase();
				trvlmdb.delete(TravelmeDatabase.USERINGROUP_TNAME, TravelmeDatabase.USERINGROUP_CIDUSER+" = "+idFriend+" AND "+TravelmeDatabase.USERINGROUP_CIDLGROUP+" = "+idGroup, null);
				trvlmdb.close();
				
				new DataManager(asyncActivity).asyncNotice(AsyncNoticeCode.UNKNOWN_ASYNC_ERROR);
			}
		}
	}
	
	/**
	 * Add a friend to a group that user is administrating.
	 * 
	 * @param idGroup Identificador del grupo
	 * @param idFriend Identificador del amigo a invitar al grupo.
	 * */
	public void addFriendTo(int idGroup, int idFriend){
		trvlmdb = databaseHelper.getWritableDatabase();
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.USERINGROUP_CIDUSER, idFriend);
		v.put(TravelmeDatabase.USERINGROUP_CIDLGROUP, idGroup);
		
		trvlmdb.insert(TravelmeDatabase.USERINGROUP_TNAME, null, v);
		trvlmdb.close();
		
		new NewAddFriendToCall(idGroup, idFriend).execute();
	}
	
	/**
	 *  Elimina un usuario de un grupo. Sólo el administrador del grupo podrá hacerlo.
	 *  Sync call.
	 *  
	 * @param idGroup Identificador del grupo.
	 * @param idFriend Identificador del amigo.
	 * 
	 * @throws ImposibleRemoveFriendFrom 
	 * */
	public void removeFriendOf(int idGroup, int idFriend) throws ImposibleRemoveFriendFrom{
		SyncInternetConnection removeFriendOfCall = new SyncInternetConnection(TRVLMWS);
		List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity),METHOD_GM, ACTION_GM_DELF);
		pairs.add(new BasicNameValuePair("gid", ""+groupManagerInstance.getGroup(idGroup).getIdOnline()));
		pairs.add(new BasicNameValuePair("fid", ""+idFriend));
		removeFriendOfCall.addGETParams(pairs);
		
		String response = removeFriendOfCall.send();
		Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
		if(answer.getState() != 0){
			throw new ImposibleRemoveFriendFrom(idGroup, idFriend);
		}
		trvlmdb = databaseHelper.getWritableDatabase();
		trvlmdb.delete(TravelmeDatabase.USERINGROUP_TNAME,
				TravelmeDatabase.USERINGROUP_CIDLGROUP+"="+idGroup+
				" AND "+
				TravelmeDatabase.USERINGROUP_CIDUSER+"="+idFriend
				, null);
		trvlmdb.close();
	}
	
	private class AddPlaceToCall extends AsyncInternetConnection{
		
		private final int idGroup;
		private final int idPlace;

		public AddPlaceToCall(int idGroup, int idPlace) {
			super(TRVLMWS);
			this.idGroup = idGroup;
			this.idPlace = idPlace;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_ADDP);
			pairs.add(new BasicNameValuePair("gid", ""+groupManagerInstance.getGroup(idGroup).getIdOnline()));
			pairs.add(new BasicNameValuePair("pid", ""+idPlace));
			
			addGETParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
			
			trvlmdb = databaseHelper.getWritableDatabase();
			if(answer.getState() != 0){
				trvlmdb.delete(TravelmeDatabase.PLACEINGROUP_TNAME, TravelmeDatabase.PLACEINGROUP_CIDGROUP+"="+idGroup+" AND "+TravelmeDatabase.PLACEINGROUP_CIDPLACE+"="+idPlace, null);
				return;
			}
			
			ContentValues v = new ContentValues();
			v.put(TravelmeDatabase.PLACEINGROUP_CSYNC, 1);
			trvlmdb.update(TravelmeDatabase.PLACEINGROUP_TNAME, v, TravelmeDatabase.PLACEINGROUP_CIDGROUP+"="+idGroup+" AND "+TravelmeDatabase.PLACEINGROUP_CIDPLACE+"="+idPlace, null);
			trvlmdb.close();
		}
	}
	
	/**
	 * Añade un lugar a un grupo.
	 * 
	 * @param idGroup Identificador del grupo.
	 * @param idPlace Identificador del lugar a agregar.
	 * */
	public void addPlaceTo(int idGroup, int idPlace){
		
		trvlmdb = databaseHelper.getWritableDatabase();
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.PLACEINGROUP_CIDGROUP, idGroup);
		v.put(TravelmeDatabase.PLACEINGROUP_CIDPLACE, idPlace);
		trvlmdb.insert(TravelmeDatabase.PLACEINGROUP_TNAME, null, v);
		trvlmdb.close();
		
		new AddPlaceToCall(idGroup, idPlace).execute();
	}
	
	private class RemovePlaceOfCall extends AsyncInternetConnection{
		private final int idGroup;
		private final int idPlace;
		public RemovePlaceOfCall(int idGroup, int idPlace) {
			super(TRVLMWS);
			
			this.idGroup = idGroup;
			this.idPlace = idPlace;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_DELP);
			pairs.add(new BasicNameValuePair("gid", ""+idGroup));
			pairs.add(new BasicNameValuePair("pid", ""+idPlace));
			
			addGETParams(pairs);
			
		}

		@Override
		protected void onPostExecute(String response) {
			Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
			trvlmdb = databaseHelper.getWritableDatabase();
			if(answer.getState() != 0){
				return;
			}
			trvlmdb.delete(TravelmeDatabase.PLACEINGROUP_TNAME, TravelmeDatabase.PLACEINGROUP_CIDGROUP+"="+idGroup+" AND "+TravelmeDatabase.PLACEINGROUP_CIDPLACE+"="+idPlace, null);
			trvlmdb.close();
		}
		
	}
	/**
	 * Elimina un lugar de un grupo.
	 * 
	 * @param idGroup Identificador del grupo.
	 * @param idPlace Identificador del lugar a eliminar.
	 * */
	public void removePlaceOf(int idGroup, int idPlace){
		trvlmdb = databaseHelper.getWritableDatabase();
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.PLACEINGROUP_CMARKTODEL, 1);
		trvlmdb.update(TravelmeDatabase.PLACEINGROUP_TNAME, v, TravelmeDatabase.PLACEINGROUP_CIDGROUP+"="+idGroup+" AND "+TravelmeDatabase.PLACEINGROUP_CIDPLACE+"="+idPlace, null);
		trvlmdb.close();
		
		new RemovePlaceOfCall(idGroup, idPlace).execute();
	}
	
	/**
	 * Accept an invitation to a group.
	 * Llamada síncrona.
	 * @throws ImposibleAcceptInvitation 
	 * */
	public void acceptInvitation(int idGroup ) throws ImposibleAcceptInvitation{
		SyncInternetConnection AcceptInvitationCall = new SyncInternetConnection(TRVLMWS);
		List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_ACCEPT);
		
		trvlmdb = databaseHelper.getReadableDatabase();
		Cursor c = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.GROUP_TNAME+" WHERE "+TravelmeDatabase.GROUP_CIDL+" = "+idGroup, null);
		c.moveToFirst();
		int idgo = c.getInt(c.getColumnIndex(TravelmeDatabase.GROUP_CID));
		pairs.add(new BasicNameValuePair("gid", ""+idgo));
		c.close();
		trvlmdb.close();
		
		AcceptInvitationCall.addGETParams(pairs);
		
		String response = AcceptInvitationCall.send();
		Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
		if(answer.getState() != 0){
			throw new ImposibleAcceptInvitation(idGroup);
		}
		
		trvlmdb = databaseHelper.getWritableDatabase();
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.USERINGROUP_CIDLGROUP, idGroup);
		int myselfid = new AccountManager(asyncActivity).getUserLogged().getId();
		v.put(TravelmeDatabase.USERINGROUP_CIDUSER, myselfid);
		
		trvlmdb.insert(TravelmeDatabase.USERINGROUP_TNAME, null, v);
		trvlmdb.close();
	}
	
	private class RejectInvitationCall extends AsyncInternetConnection{

		private final int idGroup;
		public RejectInvitationCall(int idGroup) {
			super(TRVLMWS);
			this.idGroup = idGroup;
			
			List<NameValuePair> pairs = basicGETParams(new AccountManager(asyncActivity), METHOD_GM, ACTION_GM_REJECT);
			trvlmdb = databaseHelper.getReadableDatabase();
			Cursor c = trvlmdb.rawQuery("SELECT * FROM "+TravelmeDatabase.GROUP_TNAME+" WHERE "+TravelmeDatabase.GROUP_CIDL+" = "+idGroup, null);
			c.moveToFirst();
			int idgo = c.getInt(c.getColumnIndex(TravelmeDatabase.GROUP_CID));
			pairs.add(new BasicNameValuePair("gid", ""+idgo));
			c.close();
			trvlmdb.close();
			
			addGETParams(pairs);
		}

		@Override
		protected void onPostExecute(String response) {
			Answer answer = new ParseAnswer<Answer>().parse(response, Answer.class);
			if(answer.getState() != 0){
				return;
			}
			
			trvlmdb = databaseHelper.getWritableDatabase();
			int myselfid = new AccountManager(asyncActivity).getUserLogged().getId();
			trvlmdb.delete(TravelmeDatabase.USERINGROUP_TNAME, TravelmeDatabase.USERINGROUP_CIDLGROUP+"="+idGroup+" AND "+TravelmeDatabase.USERINGROUP_CIDUSER+"="+myselfid, null);
			trvlmdb.delete(TravelmeDatabase.GROUP_TNAME, TravelmeDatabase.GROUP_CIDL+" = "+idGroup, null);
			trvlmdb.close();
		}
	}
	
	/**
	 * Reject a invitation of a group.
	 * 
	 * @param idGroup
	 * */
	public void rejectInvitation(int idGroup ){
		trvlmdb = databaseHelper.getWritableDatabase();
		
		ContentValues v = new ContentValues();
		v.put(TravelmeDatabase.USERINGROUP_CTOREJECT, 1);
		int myselfid = new AccountManager(asyncActivity).getUserLogged().getId();
		trvlmdb.update(TravelmeDatabase.USERINGROUP_TNAME, v, TravelmeDatabase.USERINGROUP_CIDLGROUP+"="+idGroup+" AND "+TravelmeDatabase.USERINGROUP_CIDUSER+"="+myselfid, null);
		
		v = new ContentValues();
		v.put(TravelmeDatabase.GROUP_TOREMOVE, 1);
		trvlmdb.update(TravelmeDatabase.GROUP_TNAME, v, TravelmeDatabase.GROUP_CIDL+" = "+idGroup, null);
		
		trvlmdb.close();
		new RejectInvitationCall(idGroup).execute();
	}
}
